// -*- mode:c++ -*-

// Copyright (c) 2009 The University of Edinburgh
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met: redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer;
// redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution;
// neither the name of the copyright holders nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Authors: Lei Zhang

////////////////////////////////////////////////////////////////////
//
// Integer ALU instructions
//


let {{

readAFRCode = 'Afr afr = AFR;\n'
setAFRCode = 'AFR = afr;\n'

# stone: We use 'afr1' instead of 'afr' as the identifier,
#   in order not to conflict with readAFRCode
updateCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRField((uint32_t)%(result)s);
    AFR = afr1;
'''

updateDCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRField((uint64_t)%(result)s);
    AFR = afr1;
'''

updateSubCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldSub((uint32_t)%(inputa)s, (uint32_t)%(inputb)s);
    AFR = afr1;
'''

# update afr based on the result of double word operations
updateDsubCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldSub((uint64_t)%(inputa)s, (uint64_t)%(inputb)s);
    AFR = afr1;
'''

updateSubcCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldSubc((uint32_t)%(inputa)s,
            (uint32_t)%(inputb)s, afr1.ca);
    AFR = afr1;
'''

# update afr based on the result of double word operations
updateDsubcCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldSubc((uint64_t)%(inputa)s, 
            (uint64_t)%(inputb)s, afr1.ca);
    AFR = afr1;
'''

updateRsubCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldRsub((uint32_t)%(inputa)s, (uint32_t)%(inputb)s);
    AFR = afr1;
'''

# update afr based on the result of double word operations
updateDrsubCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldRsub((uint64_t)%(inputa)s, (uint64_t)%(inputb)s);
    AFR = afr1;
'''

updateRsubcCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldRsubc((uint32_t)%(inputa)s,
            (uint32_t)%(inputb)s, afr1.ca);
    AFR = afr1;
'''

# update afr based on the result of double word operations
updateDrsubcCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldRsubc((uint64_t)%(inputa)s, 
            (uint64_t)%(inputb)s, afr1.ca);
    AFR = afr1;
'''

updateAddCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldAdd((uint32_t)%(inputa)s, (uint32_t)%(inputb)s);
    AFR = afr1;
'''

# update afr based on the result of double word operations
updateDaddCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldAdd((uint64_t)%(inputa)s, (uint64_t)%(inputb)s);
    AFR = afr1;
'''

updateAddcCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldAddc((uint32_t)%(inputa)s, 
            (uint32_t)%(inputb)s, afr1.ca);
    AFR = afr1;
'''

# update afr based on the result of double word operations
updateDaddcCode = '''
    Afr afr1 = AFR;
    afr1 = makeAFRFieldAddc((uint64_t)%(inputa)s, 
            (uint64_t)%(inputb)s, afr1.ca);
    AFR = afr1;
'''

def GetCondMovCode(br_code):
    cond_code =  'uint8_t afr = AFR;\n'
    cond_code += 'bool afr_ok = afrOk(afr);\n'
    cond_code += 'if(afr_ok) {\n'
    cond_code += '    ' + br_code + '\n'
    cond_code += '} else {\n'
    cond_code += '    Rd = Rd;\n'
    cond_code += '}\n'
    return cond_code

}};


// A basic integer instruction.
def format IntOp(code, inst_flags = []) {{
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};

// Integer instructions with immediate (signed or unsigned).
def format IntImmOp(code, inst_flags = []) {{
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Instructions that use source registers Ra and Rb, with the result
// placed into Rt. Basically multiply and divide instructions. The
// carry bit is never set, but overflow can be calculated. Division
// explicitly sets the overflow bit in certain situations and this is
// dealt with using the 'divSetOV' boolean in decoder.isa. We generate
// two versions of each instruction to deal with the Rc bit.
def format IntArithOp(code, ctrl_flags = [], inst_flags = []) {{

    # single and double word instructions have different sources
    # FIXME: to find a more elegant way
    if code.find('Rs1_uw') != -1:
        dict = {'result':'Rd_uw', 'inputa':'Rs1_uw', 'inputb':'Rs2_uw'}
    elif code.find('Rs1_sw') != -1: # only for mul & div
        dict = {'result':'Rd_uw'}
    else:
        dict = {'result':'Rd', 'inputa':'Rs1', 'inputb':'Rs2'}
    
    # stone: this segment of code is too long :-(
    for val in ctrl_flags:
        if val == 'update':
            code += updateCode % dict
        elif val == 'updateD':
            code += updateDCode % dict
        elif val == 'updateAdd':
            code += updateAddCode % dict
        elif val == 'updateDadd':
            code += updateDaddCode % dict
        elif val == 'updateAddc':
            code += updateAddcCode % dict
        elif val == 'updateDaddc':
            code += updateDaddcCode % dict
        elif val == 'updateSub':
            code += updateSubCode % dict
        elif val == 'updateDsub':
            code += updateDsubCode % dict
        elif val == 'updateSubc':
            code += updateSubcCode % dict
        elif val == 'updateDsubc':
            code += updateDsubcCode % dict
        elif val == 'updateRsub':
            code += updateRsubCode % dict
        elif val == 'updateDrsub':
            code += updateDrsubCode % dict
        elif val == 'updateRsubc':
            code += updateRsubcCode % dict
        elif val == 'updateDrsubc':
            code += updateDrsubcCode % dict
        else:   # may find a better way to detect this error
            print "stone's error!" 

    # stone: AFR should be read out first
    if code.find('afr.ca') != -1:
       code = readAFRCode + code 
    
    # Generate the classes
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntOp', code, inst_flags,
                 BasicDecode, BasicConstructor)

}};


// Integer instructions with immediate that perform arithmetic.
// These instructions all write to Rt and use an altered form of the
// value in source register Ra, hence the use of src to hold the actual
// value. The control flags include the use of code to compute the
// carry bit or the CR0 code.
def format IntImmArithOp(code, ctrl_flags = [], inst_flags = []) {{

    # FIXME
    if code.find('Rs1_uw') != -1:
        dict = {'result':'Rd_uw', 'inputa':'Rs1_uw', 'inputb':'uimm'}
    elif code.find('Rs1_sw') != -1: 
        dict = {'result':'Rd_uw'}
    else:
        dict = {'result':'Rd', 'inputa':'Rs1', 'inputb':'uimm'}
   
    for val in ctrl_flags:
        if val == 'update':
            code += updateCode % dict
        elif val == 'updateD':
            code += updateDCode % dict
        elif val == 'updateAdd':
            code += updateAddCode % dict
        elif val == 'updateDadd':
            code += updateDaddCode % dict
        elif val == 'updateAddc':
            code += updateAddcCode % dict
        elif val == 'updateDaddc':
            code += updateDaddcCode % dict
        elif val == 'updateSub':
            code += updateSubCode % dict
        elif val == 'updateDsub':
            code += updateDsubCode % dict
        elif val == 'updateSubc':
            code += updateSubcCode % dict
        elif val == 'updateDsubc':
            code += updateDsubcCode % dict
        elif val == 'updateRsub':
            code += updateRsubCode % dict
        elif val == 'updateDrsub':
            code += updateDrsubCode % dict
        elif val == 'updateRsubc':
            code += updateRsubcCode % dict
        elif val == 'updateDrsubc':
            code += updateDrsubcCode % dict
        else:   # may find a better way to detect this error
            print "stone's error!" 
   
    # stone: AFR should be read out first
    if code.find('afr.ca') != -1:
       code = readAFRCode + code 
    
    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};


// Integer instructions that perform logic operations. The result is
// always written into Ra. All instructions have 2 versions depending on
// whether the Rc bit is set to compute the CR0 code. This is determined
// at decode as before.
def format IntLogicOp(code, ctrl_flags = [], inst_flags = []) {{
    if code.find('Rd_uw') != -1:
        dict = {'result':'Rd_uw'}
    else:
        dict = {'result':'Rd'}

    for val in ctrl_flags:
        if val == 'update':
            code += updateCode % dict
        elif val == 'updateD':
            code += updateDCode % dict

    # Generate the first class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntOp', code, inst_flags,
                 BasicDecode, BasicConstructor)

}};

// Integer instructions with immediate that perform logic operations.
// All instructions write to Ra and use Rs as a source register. Some
// also compute the CR0 code too.
def format IntImmLogicOp(code, ctrl_flags = [], inst_flags = []) {{
    # Set up the dictionary and deal with computing CR0
    if code.find('Rd_uw') != -1:
        dict = {'result':'Rd_uw'}
    else:
        dict = {'result':'Rd'}
    
    for val in ctrl_flags:
        if val == 'update':
            code += updateCode % dict
        elif val == 'updateD':
            code += updateDCode % dict

    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmOp', code, inst_flags, BasicDecode,
                 BasicConstructor)
}};

// for cmovcc and cnotcc
def format IntLogicOpCond(code, inst_flags = []) {{
    dict = {'result':'Rd'}
    basic_code = GetCondMovCode(code)

    # Generate the first class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntOp', basic_code, inst_flags,
                 BasicDecode, BasicConstructor)
}};

// for cmovcci and cnotcci
def format IntImmLogicOpCond(code, inst_flags = []) {{
    # Set up the dictionary and deal with computing CR0
    dict = {'result':'Rd'}
    basic_code = GetCondMovCode(code)
        
    # Generate the class
    (header_output, decoder_output, decode_block, exec_output) = \
        GenAluOp(name, Name, 'IntImmOp', basic_code, inst_flags, BasicDecode,
                 BasicConstructor)
}};

